package com.green.dao.spring;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import com.green.common.ContextHolder;

/**
 * 动态数据源，不同城市，不同数据中心用不同的数据源
 * 
 * @author Hou Peiqin
 * 
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
	private final static Logger logger = Logger.getLogger(DynamicDataSource.class);
	private Map<Object, Object> backupDataSources;
	private DataSource defaultBackupDataSource;
	private String validateQuery;
	private static volatile boolean isEnableBackup = false;
	private static DynamicDataSource dynamicDataSource;

	public DynamicDataSource() {
		dynamicDataSource = this;
	}

	public void setDefaultBackupDataSource(DataSource defaultBackupDataSource) {
		this.defaultBackupDataSource = defaultBackupDataSource;
	}
	
	public void setValidateQuery(String validateQuery) {
		this.validateQuery = validateQuery;
	}

	public void init() {
		if (backupDataSources != null && backupDataSources.size() > 0) {
			new Thread(new DBMonitor()).start();
		}
	}

	/**
	 * 备用数据源，当主数据源无法连接时，自动切换备用数据源
	 * 
	 * @param backupDataSources
	 */
	public void setBackupDataSources(Map<Object, Object> backupDataSources) {
		this.backupDataSources = backupDataSources;
	}

	@Override
	protected Object determineCurrentLookupKey() {
		String key = ContextHolder.getDataSource();
		return key == null ? "greenOfficialData" : key;
	}

	@Override
	protected DataSource determineTargetDataSource() {
		if (isEnableBackup) {
			return getBackupDataSource();
		}
		return getMasterDataSource();
	}

	private DataSource getMasterDataSource() {
		return super.determineTargetDataSource();
	}
	
	private DataSource getBackupDataSource() {
		logger.warn("************************************");
		logger.warn("Current is using backup datasource");
		logger.warn("************************************");
		DataSource dataSource = (DataSource) backupDataSources.get(determineCurrentLookupKey());
		if (dataSource == null) {
			logger.warn("backup dataSource is null for lookup key [" + determineCurrentLookupKey() + "]");
			return defaultBackupDataSource;
		}
		return dataSource;
	}

	/**
	 * 数据库监听， 连续5次连接失败则认为数据库故障, 三秒检测一次
	 * 
	 */
	public class DBMonitor implements Runnable {

		@Override
		public void run() {
			int count = 0;
			for (;;) {
				Connection conn = null;
				try {
					Thread.sleep(3000);
					if(isEnableBackup){
						conn = dynamicDataSource.getBackupDataSource().getConnection();
					}else{
						conn = dynamicDataSource.getMasterDataSource().getConnection();
					}
					conn.createStatement().executeQuery(validateQuery);
				} catch (Exception e) {
					logger.error("database connect exception", e);
					count++;
					if (count >= 5) {
						isEnableBackup = !isEnableBackup;
						count = 0;
					} 
				} finally {
					if (conn != null) {
						try {
							conn.close();
						} catch (SQLException e) {
							logger.error("jdbc connection close exception", e);
						}
					}
				}
			}
		}

	}
}